/*
 * PriorityQ.cpp
 *
 *  Created on: 2013-11-12
 *      Author: all
 */


#include "PriorityQ.h"
#include "Process.h"
#include <stdio.h>
#include <list>
#include <pthread.h>
#include <iostream>
#include <unistd.h>
#include "RuntimeParameters.h"

PriorityQ* PriorityQ::instance = NULL;


PriorityQ::PriorityQ() {
	finished = FinishedQ::getInstance();

	processesRunning = 0;

	mutex = PTHREAD_MUTEX_INITIALIZER;
	hasProcesses = PTHREAD_COND_INITIALIZER;

	highPrio = std::list<Process*>();
	medPrio = std::list<Process*>();
	lowPrio = std::list<Process*>();
}

PriorityQ::~PriorityQ() {
	// TODO Auto-generated destructor stub
}

void PriorityQ::add(Process* p) {
	p->startTimer();
	// STS
	pthread_mutex_lock(&mutex);
	if(p->isFinished()) {
		finished->add(p);
		processesRunning--;
		pthread_cond_signal(&hasRoom);
	}
	else if(p->getPriorityRuntime() < MED_PRIORITY) { //if process has not exceeded high priority time of 8 - goes back into high priority
		highPrio.push_back(p);
	}
	else if(p->getPriorityRuntime() < LOW_PRIORITY) {
		medPrio.push_back(p);
	}
	else {
		lowPrio.push_back(p);
	}
	usleep(MICROSECONDS_SLEEP_TIME);
	pthread_cond_signal(&hasProcesses);
	pthread_mutex_unlock(&mutex);
}

void PriorityQ::addNew(Process* p) {
	// STS
	p->startTimer();
	pthread_mutex_lock(&mutex);
	while(processesRunning >= MAX_PROCESSES) {
		pthread_cond_wait(&hasRoom, &mutex);
	}
	if(p->isFinished()) {
		finished->add(p);
	} else {
		highPrio.push_back(p);
		processesRunning++;
	}
	pthread_cond_signal(&hasProcesses);
	pthread_mutex_unlock(&mutex);
}

Process* PriorityQ::pull() {
	// STS
	pthread_mutex_lock(&mutex);
	while(highPrio.empty() && medPrio.empty() && lowPrio.empty()) {
		pthread_cond_wait(&hasProcesses, &mutex);
	}
	usleep(MICROSECONDS_CONTENT_SWITCH_TIME);

	Process* p = NULL;

	if(!highPrio.empty()){
		p = (highPrio.front());
		highPrio.pop_front();
	} else if(!medPrio.empty()){
		p = (medPrio.front());
		medPrio.pop_front();
	} else if(!lowPrio.empty()){
		p = (lowPrio.front());
		lowPrio.pop_front();
	}
	printf("STS: Getting process%d from priorityQ\n", p->getProcessID());
	usleep(MICROSECONDS_SLEEP_TIME);
	p->stopTimer(Process::ReadyQ);
	pthread_mutex_unlock(&mutex);
	return p;
}

PriorityQ* PriorityQ::getInstance() {
	if(instance == NULL) {
		instance = new PriorityQ();
	}
	return instance;
}

void PriorityQ::resetPriorityRuntime() {

	pthread_mutex_lock(&mutex);
	for (std::list<Process*>::iterator p = highPrio.begin(); p != highPrio.end(); p++) {
		(*p)->setPriorityRuntime(0);
	}
	for (std::list<Process*>::iterator p = medPrio.begin(); p != medPrio.end(); p++) {
		(*p)->setPriorityRuntime(0);
	}
	for (std::list<Process*>::iterator p = lowPrio.begin(); p != lowPrio.end(); p++) {
		(*p)->setPriorityRuntime(0);
	}
	pthread_mutex_unlock(&mutex);
}



